<template>
  <el-dialog v-model="dialogVisible" :destroy-on-close="true" width="840px" :title="`${dialogProps.title}`">
    <div class="dig-box">
      <ProTable
        ref="proTable"
        row-key="id"
        default-expand-all
        :columns="columns"
        :data="tableData"
        :tool-button="false"
        :pagination="false"
        :tree-props="{ children: 'childrens' }"
        @select="select"
        @select-all="selectAll"
      >
        <template #operation="scope">
          <el-checkbox
            v-model="item.check"
            v-for="(item, index) in scope.row.dictList"
            :key="index"
            :label="item.id"
            @change="ev => onChangeBtn(ev, scope.row)"
          >
            {{ item.title }}
          </el-checkbox>
        </template>
      </ProTable>
    </div>
    <template #footer>
      <el-button @click="dialogVisible = false"> 取消 </el-button>
      <el-button v-show="!dialogProps.isView" type="primary" @click="handleSubmit"> 确定 </el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts" name="RoleDialog">
import { ref } from "vue";
import { ElMessage } from "element-plus";
import ProTable from "@/components/ProTable/index.vue";
import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
import { getLoadMenuPageDictList } from "@/api/modules/system";

const proTable = ref<ProTableInstance>();
interface DialogProps {
  title: string;
  isView: boolean;
  id: number;
  api?: (params: any) => Promise<any>;
  getTableList?: () => void;
}

interface nodeItem {
  check: boolean;
  id: string | number;
  name: string;
  parentId: string | number;
  path: string;
  redirect: string;
  sort: number;
  childrens?: nodeItem[];
}

const columns: ColumnProps[] = [
  { type: "selection", width: 60 },
  { prop: "title", label: "菜单名称", width: 200, align: "left" },
  { prop: "operation", label: "按钮权限", align: "left" }
];
const tableData = ref<nodeItem[]>([]);
const dialogVisible = ref(false);
const dialogProps = ref<DialogProps>({
  isView: false,
  title: ""
});

const defaultCheckedKeys = ref([]);

const setSelection = (data: any) => {
  data.forEach(im => {
    if (im.check) {
      proTable.value!.element.toggleRowSelection(im, true);
    }
    if (im.childrens.length > 0) {
      setSelection(im.childrens);
    }
  });
};

const permissions = (list: any[], val: boolean) => {
  list.forEach(im => {
    if (im.childrens.length === 0) {
      im.dictList.forEach(bts => {
        bts.check = val;
      });
    } else {
      permissions(im.childrens, val);
    }
  });
};

const onChangeBtn = (ev: boolean, row: any) => {
  if (ev) {
    proTable.value!.element.toggleRowSelection(row, true);
  }
};

// 接收父组件传过来的参数
const acceptParams = (params: DialogProps) => {
  dialogProps.value = params;
  getLoadMenuPageDictList({ id: dialogProps.value.id }).then(res => {
    tableData.value = res.data;
    setSelection(tableData.value);
  });
  dialogVisible.value = true;
  defaultCheckedKeys.value = [];
};

// 全选 反选
const selectAll = (selection: nodeItem[]) => {
  // tabledata第一层只要有在selection里面就是全选
  const isSelect = selection.some((el: nodeItem) => {
    const tableDataPaths = tableData.value.map((j: nodeItem) => j.id);
    return tableDataPaths.includes(el.id);
  });
  // tableDate第一层只要有不在selection里面就是全不选
  const isCancel = !tableData.value.every((el: nodeItem) => {
    const selectPaths = selection.map(j => j.id);
    return selectPaths.includes(el.id);
  });
  if (isCancel) {
    tableData.value.map((el: nodeItem) => {
      if (el.childrens) {
        // 解决子组件没有被勾选到
        setChildren(el.childrens, false);
      }
    });
  }
  if (isSelect) {
    selection.map(el => {
      if (el.childrens) {
        // 解决子组件没有被勾选到
        setChildren(el.childrens, true);
      }
    });
  }
  if (selection.length > 0) {
    permissions(tableData.value, true);
  } else {
    permissions(tableData.value, false);
  }
};

// 设置父级选中/取消
const setParent = (currentRow: any, type: boolean, parent: nodeItem[], selectionLists: nodeItem[]) => {
  if (!parent.length) {
    parent = tableData.value;
  }
  let allSelect: any[] = [];
  parent.forEach((item: nodeItem) => {
    if (item.childrens.length > 0) {
      if (currentRow.parentId === item.id) {
        // 选中
        if (type) {
          selectionLists.forEach((k: nodeItem) => {
            item.childrens?.forEach((j: nodeItem) => {
              if (k.id == j.id) {
                allSelect.push(j);
              }
            });
          });
          if (allSelect.length == item.childrens.length) {
            toggleSelection(item, type);
            selectionLists.push(item);
            select(selectionLists, item);
          } else {
            setParent(currentRow, type, item.childrens, selectionLists);
          }
        } else {
          // 取消选中
          toggleSelection(item, type);
          setParent(currentRow, type, item.childrens, []);
        }
      }
    }
  });
};

// 选中父节点时，子节点一起选中/取消
const select = (selection: nodeItem[], row: nodeItem) => {
  const hasSelect = selection.some((el: nodeItem) => {
    return row.id === el.id;
  });
  if (hasSelect) {
    if (row.childrens.length > 0) {
      // 解决子组件没有被勾选到
      setChildren(row.childrens, true);
    }
    // 子节点被全勾选，父节点也勾上
    setParent(row, true, [], selection);
  } else {
    if (row.childrens.length > 0) {
      setChildren(row.childrens, false);
    }
    // 子级取消选中, 传入当前选中节点, 所有父级取消选中
    setParent(row, false, [], []);
  }
};

const setChildren = (children: nodeItem[], type: boolean) => {
  // 编辑多个子层级
  children.map((j: nodeItem) => {
    toggleSelection(j, type);
    if (j.childrens) {
      setChildren(j.childrens, type);
    }
  });
};

const toggleSelection = (row: nodeItem, select: boolean) => {
  // 编辑多个子层级
  if (row) {
    proTable.value?.element.toggleRowSelection(row, select);
  }
};

const flattenTree = (data: nodeItem[]) => {
  let newData = [];
  const callback = item => {
    (item.childrens || (item.childrens = [])).map(v => {
      callback(v);
    });
    delete item.childrens;
    newData.push(item);
  };
  data.map(v => callback(v));
  function removeDuplicatesById(items: Item[]): Item[] {
    return items.filter((item, index) => {
      const foundIndex = items.findIndex(other => other.id === item.id);
      return foundIndex === index;
    });
  }
  newData = removeDuplicatesById(newData);
  return newData;
};

// 提交数据（新增/编辑）
const handleSubmit = async () => {
  try {
    await dialogProps.value.api!({ id: dialogProps.value.id, data: flattenTree(proTable.value.selectedList) });
    ElMessage.success({ message: `设置成功！` });
    dialogVisible.value = false;
  } catch (error) {
    console.log(error);
  }
};

defineExpose({
  acceptParams
});
</script>
<style lang="scss" scoped>
.dig-box {
  height: 560px;
  overflow: scroll;
}
</style>
